#!/usr/bin/env python
# -*- coding: utf-8 -*-

from typing import Any

from cta.interface.action.update_optimize2_account.abstract_update_optimize2_account_action import \
    AbstractUpdateOptimize2AccountAction
from web.constants.datetime_format import DatetimeFormat
from web.constants.direction import Direction
from web.domain.responsibility_chain_dto import ResponsibilityChainDto
from web.manager.log_manager import LogManager
from web.models import CommodityFutureInfo
from web.models.commodity_future_date_contract_data import CommodityFutureDateContractData
from web.models.optimize2_account import Optimize2Account
from web.models.optimize2_commodity_future_transaction_record import Optimize2CommodityFutureTransactionRecord
from web.util.commodity_future_code_util import CommodityFutureCodeUtil
from web.util.datetime_util import DatetimeUtil
from web.util.fee_util import FeeUtil

Logger = LogManager.get_logger(__name__)

class UpdateOptimize2AccountAfterOverweightAction(AbstractUpdateOptimize2AccountAction):
    """
    加仓后更新optimize2_account表动作
    """

    def exec(self, responsibility_chain_dto: ResponsibilityChainDto = None) -> Any:
        Logger.info("加仓后更新optimize2_account表")

        transaction_date: str = responsibility_chain_dto.transaction_date

        # 根据持仓时间，判断当天是否应当平仓和开仓。判断当天是否应该减仓或加仓
        if responsibility_chain_dto.has_overweight is True or (responsibility_chain_dto.has_overweight is False and responsibility_chain_dto.has_update_optimize2_account_after_open_position is False):
        # if (responsibility_chain_dto.underweight is True and self.optimize2_close_or_open_position_by_holding_position_time(transaction_date) is False) \
        #         or (responsibility_chain_dto.underweight is False and self.optimize2_close_or_open_position_by_holding_position_time(transaction_date) is True):
        # if not self.close_or_open_position_by_up_down_percentage_with_n_date(transaction_date):

            # 返回量化账户
            optimize2_account_list: list[Optimize2Account] = self.optimize2_account_dao.find_all()

            for optimize2_account in optimize2_account_list:
                # 期货资产
                commodity_future_assets: float = 0.0
                # 当天开仓的期货资产
                current_open_commodity_future_assets: float = 0.0
                # 买入期货品种的数量
                sell_or_buy_commodity_future_number: int = 0

                # 计算每一个量化账户，在某一天开仓后的收益
                optimize2_commodity_future_transaction_record_list: list[Optimize2CommodityFutureTransactionRecord] = self.optimize2_commodity_future_transaction_record_dao.find_by_account_name_and_not_close_position(optimize2_account.account_name)

                # 如果没有开仓期货，则直接将optimize2_account表中的记录插入到optimize2_account_log表中
                if optimize2_commodity_future_transaction_record_list is None or len(optimize2_commodity_future_transaction_record_list) == 0:
                    continue

                for optimize2_commodity_future_transaction_record in optimize2_commodity_future_transaction_record_list:
                    # 查找某个期货在某一天的收盘价
                    # 期货的收盘价
                    commodity_future_date_contract_data: CommodityFutureDateContractData = self.commodity_future_date_contract_data_dao.find_by_code_and_transaction_date(optimize2_commodity_future_transaction_record.code, transaction_date)

                    if commodity_future_date_contract_data is None:
                        # 说明期货在这一天没有交易记录
                        Logger.warning("期货[%s]在日期[%s]没有交易记录，开始查找前一个交易日的记录", optimize2_commodity_future_transaction_record.code, transaction_date)

                        # 如果在某一天没有收盘价，则查找最近一个交易日的收盘价
                        commodity_future_date_contract_data = self.commodity_future_date_contract_data_dao.find_last_commodity_future_date_contract_data_by_code_and_date(optimize2_commodity_future_transaction_record.code, transaction_date)

                    # 查询commodity_future_info记录（大小写不敏感的精确匹配查询）
                    filter_dict = {'code__iexact': CommodityFutureCodeUtil.code_to_contract_code(commodity_future_date_contract_data.code)}
                    commodity_future_info: CommodityFutureInfo = self.commodity_future_info_dao.find_one(filter_dict, dict(), list())

                    # 开仓期货后，正在持有的期货资产、持有期货的数量
                    if optimize2_commodity_future_transaction_record.direction == Direction.Up and optimize2_commodity_future_transaction_record.buy_date is not None and optimize2_commodity_future_transaction_record.sell_date is None:
                        commodity_future_assets = commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.buy_price, commodity_future_info, optimize2_commodity_future_transaction_record.buy_lot) \
                                                  + FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction, optimize2_commodity_future_transaction_record.buy_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, optimize2_commodity_future_transaction_record.buy_lot)
                        sell_or_buy_commodity_future_number = sell_or_buy_commodity_future_number + 1
                    if optimize2_commodity_future_transaction_record.direction == Direction.Down and optimize2_commodity_future_transaction_record.sell_date is not None and optimize2_commodity_future_transaction_record.buy_date is None:
                        commodity_future_assets = commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.sell_price, commodity_future_info, optimize2_commodity_future_transaction_record.sell_lot) \
                                                  + FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction, optimize2_commodity_future_transaction_record.sell_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, optimize2_commodity_future_transaction_record.sell_lot)
                        sell_or_buy_commodity_future_number = sell_or_buy_commodity_future_number + 1

                    # 开仓期货后，当天开仓的期货资产
                    if optimize2_commodity_future_transaction_record.direction == Direction.Up and optimize2_commodity_future_transaction_record.sell_date is None and optimize2_commodity_future_transaction_record.buy_date == DatetimeUtil.str_to_datetime(transaction_date, DatetimeFormat.Date_Format):
                        current_open_commodity_future_assets = current_open_commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.buy_price, commodity_future_info, optimize2_commodity_future_transaction_record.buy_lot) \
                                                                + FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction, optimize2_commodity_future_transaction_record.buy_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, optimize2_commodity_future_transaction_record.buy_lot)
                    if optimize2_commodity_future_transaction_record.direction == Direction.Down and optimize2_commodity_future_transaction_record.buy_date is None and optimize2_commodity_future_transaction_record.sell_date == DatetimeUtil.str_to_datetime(transaction_date, DatetimeFormat.Date_Format):
                        current_open_commodity_future_assets = current_open_commodity_future_assets + FeeUtil.calculate_open_commodity_future_cost(optimize2_commodity_future_transaction_record.sell_price, commodity_future_info, optimize2_commodity_future_transaction_record.sell_lot) \
                                                                + FeeUtil.calculate_actual_profit_and_loss(optimize2_commodity_future_transaction_record.direction, optimize2_commodity_future_transaction_record.sell_price, commodity_future_date_contract_data.close_price, commodity_future_info.transaction_multiplier, optimize2_commodity_future_transaction_record.sell_lot)

                # 根据账户名称，计算所有期货（包括正在持仓的和已经平仓的）的open_commission的和
                total_open_position_commission: float = self.optimize2_commodity_future_transaction_record_dao.sum_open_commission_by_account_name(optimize2_account.account_name)
                # 根据账户名称，计算所有期货（包括正在持仓的和已经平仓的）的close_commission的和
                total_close_position_commission: float = self.optimize2_commodity_future_transaction_record_dao.sum_close_commission_by_account_name(optimize2_account.account_name)
                # 根据账户名称和日期，计算某一天的开仓费用（open_commission，包括做多和做空）之和
                current_open_position_commission: float = self.optimize2_commodity_future_transaction_record_dao.sum_open_commission_by_account_name_and_date(optimize2_account.account_name, transaction_date)
                # 更新optimize2_account表
                self.optimize2_account_dao.update_after_open_position(sell_or_buy_commodity_future_number, commodity_future_assets, current_open_commodity_future_assets,
                                                total_open_position_commission, current_open_position_commission, optimize2_account.account_name)
        else:
            Logger.info("日期[%s]不应当平仓和开仓，也不应该减仓或加仓", transaction_date)
            responsibility_chain_dto.has_update_optimize2_account_after_open_position = False
            super().next(responsibility_chain_dto)
            return

        responsibility_chain_dto.has_update_optimize2_account_after_open_position = True
        super().next(responsibility_chain_dto)